#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
import time
from typing import Union, Dict

from pandas import Series, DataFrame, to_datetime

from core import threadLocal
from core.dataClasses import StockTradeDataColumnName, Event, R
from core.enums import EventType, DateFormat, Period, ThreadName
from domain.transaction_data.repository import transaction_data_repository
from event.event_manager import EventManager
from core.clock import Clock
from core import logger
from infrastructure.util import dateutils


class Context:
    """"""
    instances = {
        "default": None
    }

    @classmethod
    def getInstance(cls, name: str = "default"):
        if name is None:
            name = "default"
        if name not in cls.instances or cls.instances[name] is None:
            cls.instances[name] = cls(name)
        try:
            threadLocal.get(ThreadName.CONTEXT.value)
        except:
            threadLocal.add(ThreadName.CONTEXT.value, name)
        return cls.instances[name]

    def __init__(self, name: str):
        self.security: str = None
        self.period: Period = None
        self.event_manager: EventManager = EventManager.getInstance(threadLocal.get(ThreadName.EVENT_MANAGER.value))
        # self.event_manager.addEventListener(eventType=EventType.TIME_UPDATED, handler=self.timeUpdated)
        self.clock: Clock = Clock.getInstance(threadLocal.get(ThreadName.CLOCK.value))
        self.data: Dict[str, DataFrame] = {}
        r = R.sucess(f"初始化上下文成功")
        self.event_manager.emit(Event(EventType.TIP_COMMON, r))
        logger.info(r)

    def setDefaultPeriod(self, period: Period = Period.day):
        r = R.sucess(f"设置股票分析周期：{self.period.name if self.period is not None else 'None'} -> {period.name}")
        self.event_manager.emit(Event(EventType.TIP_COMMON, r))
        logger.info(r)

        self.period = period
        if self.security is not None and period.name not in self.data:
            self.acquire_data()

    def getData(self, period: Period = Period.day) -> DataFrame:
        if period.name in self.data:
            ldt = self.clock.getPeriodLastestTradingDatetime(self.period)
            try:
                if self.data[period.name] is None or self.data[period.name].loc[ldt.strftime(DateFormat.Y_m_d_H_M_S.value)].empty:
                    self.acquire_data()
            except KeyError:
                self.acquire_data()
        else:
            self.acquire_data()
        return self.data[period.name]

    def set_Security(self, security: str, period: Period = None):
        self.data = {}
        if period is not None:
            self.setDefaultPeriod(period)
        if security is not None and security != self.security:
            self.security = security
            self.acquire_data()

    # @logger.catch
    def acquire_data(self):
        if self.period is None:
            self.period = Period.day
        # 计算当前之前count个交易日的日期
        self.data[self.period.name] = transaction_data_repository.get_stock_transaction_data(self.security, self.period, self.clock.getPeriodLastestTradingDatetime(self.period))

        r = R.sucess(f"获取数据成功：股票代码[{self.security}],周期[{self.period.name}]")
        self.event_manager.emit(Event(EventType.TIP_COMMON, r))
        logger.info(r)

    def realtimeQuote(self):
        dt = self.clock.getDateTime()
        if self.clock.isInRealTradeTime():
            d = transaction_data_repository.realtimeQuote(self.security)
            d[StockTradeDataColumnName.TRADE_DATE.value] = dateutils.getPeriodLastestTradingDatetime(self.period)
            if d is None:
                return None
            if self.period in [Period.minute30, Period.minute5, Period.minute1]:
                todayBeforeDayVolSum = self.getData(self.period).loc[dt.strftime(DateFormat.Y_m_d.value)][StockTradeDataColumnName.VOL.value].sum()-self.data[self.period.name].loc[to_datetime(d[StockTradeDataColumnName.TRADE_DATE.value].values[0]).strftime(DateFormat.Y_m_d_H_M_S.value)][StockTradeDataColumnName.VOL.value].sum()
                d[StockTradeDataColumnName.VOL.value] = d[StockTradeDataColumnName.VOL.value] - todayBeforeDayVolSum
            return d
        else:
            if dt is None:
                dt = self.getNextPeriodDatetime()
            d = transaction_data_repository.get_stock_transaction_data(self.security, self.period, dt)
            end = dt + datetime.timedelta(seconds=1)
            return d.loc[dt.strftime(DateFormat.Y_m_d_H_M_S.value):end.strftime(DateFormat.Y_m_d_H_M_S.value), :]
        return None

    def getColumn(self, columnName: str=StockTradeDataColumnName.CLOSE.value) -> Series:
        result = self.getData(self.period)[columnName]
        return result

    def __call__(self, e: Event):
        if isinstance(e, Event):
            if e.type == EventType.TIME_UPDATED:
                pass

    def getNextPeriodDatetime(self):
        delta = datetime.timedelta(days=1)
        if self.period == Period.minute30:
            delta = datetime.timedelta(minutes=30)
        elif self.period == Period.minute5:
            delta = datetime.timedelta(minutes=5)
        elif self.period == Period.minute1:
            delta = datetime.timedelta(minutes=1)
        elif self.period == Period.week:
            delta = datetime.timedelta(weeks=1)

        dtRel = self.clock.getDateTime()
        if self.clock.isInRealTradeTime():
            dtRel = dtRel + delta
            hms = dtRel.hour*10000 + dtRel.minute*100 + dtRel.second
            if 93000 < hms <= 113000 or 130000 <= hms <= 150000:
                return dtRel
        else:
            hms = dtRel.hour * 10000 + dtRel.minute * 100 + dtRel.second
            if 93000 <= hms < 113000 or 130000 <= hms < 150000:
                dtRel = dtRel + delta
                return dtRel
            elif hms == 113000:
                dtRel = dtRel.replace(hour=13, minute=0)
                dtRel = dtRel + delta
                return dtRel
            elif hms == 150000:
                dtRel = dtRel + datetime.timedelta(days=1)
                dtRel = dtRel.replace(hour=9, minute=30)
                dtRel = dtRel + delta
                return dtRel
        return None




if __name__ == "__main__":
    context = Context("002044.SZ")
    context.acquire_data()
    print(context.data)
